(function(angular) {
	'use strict';
	angular.module("fs.waf").run(main);
	
	main.$inject = [ '$rootScope', '$timeout', '$location', '$state', '$stateParams', '$translate', '$q', '$window', '$ocLazyLoad', '$parse', 'Constants', 'loggerFactory',
			'ajaxServiceFactory', 'storageService', 'StorageConstants', 'modalService', 'commonService', 'routerService', 'ChartJs'];
	function main($rootScope, $timeout, $location, $state, $stateParams, $translate, $q, $window, $ocLazyLoad, $parse, Constants, loggerFactory, ajaxServiceFactory,
			storageService, StorageConstants, modalService, commonService, routerService, ChartJs) {
		var log = loggerFactory.getLogger('fs.waf');
		$rootScope.loggerFactory = loggerFactory;
		$rootScope.$state = $state;
		$rootScope.$stateParams = $stateParams;
		$rootScope.removePageDescription = function() {
			if (angular.isFunction($rootScope.pageDescriptionWtcher)) {
				$rootScope.pageDescriptionWtcher();
			}
			delete $rootScope.pageDescription;
		}
		$rootScope.setPageDescription = function(p) {
			if ($rootScope.pageDescriptionWatcher) {
				$rootScope.pageDescriptionWatcher();
			}
			if (angular.isFunction(p)) {
				$rootScope.pageDescriptionWtcher = $rootScope.$watch(p, function(description) {
					$rootScope.pageDescription = description;
				});
			} else {
				$rootScope.pageDescription = p;
			}
		};
		$rootScope.copyPageIdTooltip = "label.copy.pageid";
		if (!$rootScope.dataType || !$rootScope.dataKey) {
			$rootScope.disabledAuditOrNote= true;
		} else {
			$rootScope.disabledAuditOrNote= false;
		}
		$rootScope.I18N = {
			language : 'en_US'
		};
		$rootScope.setLogLevel = function() {
			loggerFactory.setLevel($rootScope.app.settings.logLevel, '*');
		};
		$rootScope.backTo = function() {
			var state = storageService.getLastHistory() || [];
			var lastUrl = state.fromUrl || [];
			var lastParams = state.fromParams || [];
			if (lastUrl) {
				lastParams._isBack = true;
				$rootScope.go(lastUrl, lastParams);
			}
		};
		$rootScope.go = function(state, params) {
			if (!state) {
				return;
			}
			$rootScope.unloadCheck().then(function() {
				var toState = routerService.parseState(state);
				var toParams = {
					'params' : angular.merge({
						__originalState : $state.current.name,
						__state : toState
					}, (params || {}))
				};
				$state.go(toState, toParams, {
					location : true,
					// inherit: false,
					reload : toState
				});
			}, angular.noop);
		};
		$rootScope.copySuccess = function() {
			$rootScope.copyPageIdTooltip = "label.copy.copied";
			$timeout(function() {
				$rootScope.copyPageIdTooltip = "label.copy.pageid";
			}, 2000);
		};
		$rootScope.defaultMouseEvent = function($event) {
			$event.preventDefault();
			$event.stopPropagation();
		};
		//audit
		$rootScope.viewAuditTooltip = "label.audit.viewaudit";
		$rootScope.viewAudit = function() {
			var params = {
				'dataType' : $rootScope.dataType,
				'dataKey' : $rootScope.dataKey
			};
			modalService.openCustomDialogs({
				'title' : 'title.dialogs.auditlistpopup',
				'dialogsModule' : 'waf.audit.popuplist',
				'params' : params,
				'btnCallback' : {
					'ok' : function(qaChoiceCtrl) {
					}
				}
			});
		};
		//adminNote
		$rootScope.createNoteTooltip = "label.note.create";
		$rootScope.createNote = function() {
			var dataType = $rootScope.dataType, isForTxn = false, title, dialogsModule, url;
			for(var i = 0; i < Constants.TXN_DATATYPES.length; i++) {
				if(dataType ==  Constants.TXN_DATATYPES[i]) {
					isForTxn = true;
					break;
				}
			}
			if(!isForTxn) {
				title = 'title.dialogs.adminnote';
				dialogsModule = 'cda.adminNote.popupCreate';
				url = 'do/cda/adminNote/create/submit';
			} else {
				title = 'title.dialogs.txnnote';
				dialogsModule = 'cda.txnNote.popupCreate';
				url = 'do/cda/txnNote/create/submit';
			}
			var params = {
				'dataType' : dataType,
				'dataKey' : $rootScope.dataKey,
				'dataStatus' : $rootScope.dataStatus,
				'serviceCode' : $rootScope.serviceCode,
				'taskId' : $rootScope.taskId
			};
			modalService.openCustomDialogs({
				'title' : title,
				'dialogsModule' : dialogsModule,
				'params' : params,
				'btnCallback' : {
					'ok' : function(returnObj) {
						var ajaxService = ajaxServiceFactory.buildAjaxService({
							createSubmit : {
								url : url,
								method : 'post'
							}
						});
						var defer = $q.defer();
						ajaxService.createSubmit(returnObj).then(function(response) {
							defer.resolve(response);
						});
						return defer.promise;
					}
				}
			});
		};
		$rootScope.removeAuditOrNoteParams = function() {
			delete $rootScope.dataType;
			delete $rootScope.dataKey;
			delete $rootScope.dataStatus;
			//delete $rootScope.serviceCode;
			delete $rootScope.taskId;
			$rootScope.disabledAuditOrNote = true;
		};
		$rootScope.saveAuditAndNoteParams = function(toState, toParams) {
			var serviceCode, stateArray, params;
			if (!toState) {
				return;
			}
			stateArray = toState.split('_');
			if (stateArray[1] == 'app') {
				serviceCode = stateArray[2];
			}
			if (toParams && toParams.params) {
				params = toParams.params;
				$rootScope.initAuditOrNoteParams(params.dataType || params.currentDataType, params.dataKey || params.primaryKey, params.dataStatus, serviceCode);
			} else {
				$rootScope.initAuditOrNoteParams('', '', '', serviceCode);
			}
		};
		$rootScope.initAuditOrNoteParams = function(dataType, dataKey, dataStatus, serviceCode, taskId) {
			$rootScope.dataType = dataType;
			$rootScope.dataKey = dataKey;
			$rootScope.dataStatus = dataStatus;
			$rootScope.serviceCode = serviceCode;
			$rootScope.taskId = taskId;
			if (!$rootScope.dataType || !$rootScope.dataKey) {
				$rootScope.disabledAuditOrNote= true;
			} else {
				$rootScope.disabledAuditOrNote= false;
			}
		};
		$rootScope.removeFormState = function() {
			delete $rootScope._isUnloadCheck;
			delete $rootScope._formName;
			delete $rootScope._isUnloadCheck;
			delete $rootScope._formScope;
			delete $rootScope._formDataKey;
			delete $rootScope._formFields;
			delete $rootScope._formDataHashCode;
		};
		$rootScope.initFormState = function(scope, formDataKey, formName) {
			if ($rootScope._formName && $rootScope._formName != formName) {
				return;
			}
			if (formDataKey.indexOf('.searchCriteria') >= 0 || !scope.fsGridLayoutController || !scope.fsGridLayoutController.fsConfig) {
				return;
			}
			$rootScope._isUnloadCheck = true;
			$rootScope._formName = formName;
			$rootScope._formScope = $rootScope._formScope || {};
			$rootScope._formScope[formDataKey] = scope;
			$rootScope._formDataKey = $rootScope._formDataKey || [];
			$rootScope._formDataKey.push(formDataKey);
			$rootScope._formFields = $rootScope._formFields || [];
			$rootScope._formFields[formDataKey] = getPageFormFields(scope.fsGridLayoutController.fsConfig);
			$rootScope._formDataHashCode = $rootScope._formDataHashCode || {};
			$rootScope._formDataHashCode[formDataKey] = commonService.hash(getPageFormData(scope.$eval(formDataKey), $rootScope._formFields[formDataKey]));
			$window.onbeforeunload = isFormChanged;
		};
		$rootScope.initFormTableState = function(scope, tableOptions, formName) {
			if ($rootScope._formName && $rootScope._formName != formName) {
				return;
			}
			if (!tableOptions.data || !angular.isString(tableOptions.data) || !tableOptions.columnDefs) {
				return;
			}
			//fixed issue for open audit then close then click the other menu.
			if (tableOptions.data.indexOf('.searchCriteria') >= 0) {
				return;
			}
			$rootScope._isUnloadCheck = true;
			$rootScope._formName = formName;
			$rootScope._formScope = $rootScope._formScope || {};
			$rootScope._formScope[tableOptions.data] = scope;
			$rootScope._formDataKey = $rootScope._formDataKey || [];
			$rootScope._formDataKey.push(tableOptions.data);
			$rootScope._formFields = $rootScope._formFields || [];
			$rootScope._formFields[tableOptions.data] = getPageFormFields(tableOptions.columnDefs);
			$rootScope._formDataHashCode = $rootScope._formDataHashCode || {};
			$rootScope._formDataHashCode[tableOptions.data] = commonService.hash(getPageFormData(scope.$eval(tableOptions.data), $rootScope._formFields[tableOptions.data]));
			$window.onbeforeunload = isFormChanged;
		};
		$rootScope.disableUnloadCheck = function() {
			delete $rootScope._isUnloadCheck;
			$window.onbeforeunload = null;
		};
		$rootScope.unloadCheck = function() {
			var defer = $q.defer();
			if (!$rootScope._isUnloadCheck || !$rootScope._formScope) {
				$rootScope._isUnloadCheck = true;
				$window.onbeforeunload = isFormChanged;
				defer.resolve(true);
			} else if(hasChanged()){
				modalService.openConfirmDialogs({
					'messages' : [ 'Are you sure to leave this page?' ],
					'btnCallback' : {
						'ok' : function(response) {
							defer.resolve(true);
						},
						'close' : function(response) {
							defer.reject(false);
						}
					}
				});
			} else {
				defer.resolve(true);
			}
			return defer.promise;
		};
		$rootScope.buildAuthService = function(authorizationConfig) {
			var authorizationServices = {};
			angular.forEach(authorizationConfig, function(value, key) {
				authorizationServices[key] = {
					url : 'do/' + value,
					method : 'post'
				};
			});
			return ajaxServiceFactory.buildAjaxService(authorizationServices);
		};
		$rootScope.showLog = function() {
			var logContent = storageService.getLog();
			var logs = [];
			angular.forEach(logContent, function(value, key) {
				this.push(value.content);
			}, logs);
			modalService.openLogDialogs({
				title : 'label.title.log',
				messages : logs.join('\n')
			});
		};
		$rootScope.saveHistory = function(event, toState, toParams, fromState, fromParams) {
			if (toParams.params && toParams.params._isBack) {
				storageService.popHistory();
			}
			if (fromState.name && (!toParams.params || !toParams.params._isBack) && !isIgnoreHistory(fromState)) {
				storageService.saveHistory({
					pageId : $rootScope.pageId,
					fromUrl : fromState.name,
					fromParams : fromParams.params,
					toUrl : toState.name,
					toParams : toParams.params
				});
			}
		};
		$rootScope.loadResource = function(resources) {
			if (resources) {
				storageService.setItemToSession(Constants.SESSION_I18N_RESOURES, resources);
				$rootScope.$emit(Constants.NOTIFY_CHANGE_LANGUAGE);
			}
		};
		$rootScope.$on(Constants.NOTIFY_CHANGE_LANGUAGE, function($event, param) {
			$event.preventDefault();
			$event.stopPropagation();
			if (param) {
				angular.extend($rootScope.I18N, param);
			}
			if ($translate.use() == $rootScope.I18N.language) {
				$translate.refresh($translate.use());
			} else {
				$translate.use($rootScope.I18N.language);
			}
		});
		$rootScope.$on(Constants.NOTIFY_REDIRECT, function($event, param) {
			$event.preventDefault();
			$event.stopPropagation();
			window.location.href = param.url;
		});
		$rootScope.$on(Constants.NOTIFY_UNAUTHORIZED, function($event, response) {
			$event.preventDefault();
			$event.stopPropagation();
			$rootScope.disableUnloadCheck();
			storageService.clearAllFromSession();
			// storageService.clearAllFromLocal();
			delete $rootScope.user;
			delete $rootScope.site;
			delete $rootScope.menus;
			if (!$stateParams.params || ($stateParams.params.__originalState != 'signon' && $state.$current.name != 'signon')) {
				$rootScope.go('signon');
			}
		});
		$rootScope.$on(Constants.NOTIFY_PAGE_NOT_FOUNT, function($event, response) {
			$event.preventDefault();
			$event.stopPropagation();
			$rootScope.disableUnloadCheck();
			$rootScope.go('waf.error.E404', response.error);
		});
		$rootScope.$on(Constants.NOTIFY_SYSTEM_ERROR, function($event, response) {
			$event.preventDefault();
			$event.stopPropagation();
			$rootScope.disableUnloadCheck();
			$rootScope.go('waf.error.E500', response.error);
		});
		$rootScope.$on(Constants.NOTIFY_CUSTOMER_ERROR, function($event, response) {
			$event.preventDefault();
			$event.stopPropagation();
			//TODU: popup error message
		});
		
		ChartJs.Chart.defaults.global.defaultFontFamily = "'Interstate', Arial, sans-serif";
		ChartJs.Chart.scaleService.updateScaleDefaults('linear', {
			ticks : {
				min : 0
			}
		});
		ChartJs.Chart.defaults.global.multiTooltipTemplate = '<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%= value %>';
		ChartJs.Chart.defaults.global.tooltips.mode = 'label';
		ChartJs.Chart.defaults.global.elements.line.borderWidth = 1;
		ChartJs.Chart.defaults.global.elements.arc.borderWidth = 1;
		ChartJs.Chart.defaults.global.elements.rectangle.borderWidth = 1;
		ChartJs.Chart.defaults.global.legend.display = false;
		// ChartJs.Chart.defaults.global.elements.line.backgroundColor = 'transparent';
		  
		// write text plugin
		ChartJs.Chart.pluginService.register({
			id : 'drawDoughnutCenterText',
			afterUpdate : function(chartController) {
				var helpers = ChartJs.Chart.helpers, globalConfig, ctx, fontStyle, fontFamily, fontSize, maxFontSize, maxText, datas, center1, center2;
				var centers = chartController.config.options.elements.center;
				if (centers) {
					globalConfig = ChartJs.Chart.defaults.global;
					ctx = chartController.chart.ctx;

					fontStyle = helpers.getValueOrDefault(centers[0].fontStyle, globalConfig.defaultFontStyle);
					fontFamily = helpers.getValueOrDefault(centers[0].fontFamily, globalConfig.defaultFontFamily);

					if (centers[0].fontSize) {
						fontSize = centers[0].fontSize;
					} else {
						// figure out the best font size, if one is not specified
						ctx.save();
						fontSize = helpers.getValueOrDefault(centers[0].minFontSize, 1);
						maxFontSize = helpers.getValueOrDefault(centers[0].maxFontSize, 256);
						maxText = helpers.getValueOrDefault(centers[0].text, centers[0].text);
						do {
							ctx.font = helpers.fontString(fontSize, fontStyle, fontFamily);
							var textWidth = ctx.measureText(maxText).width;
							if (textWidth < chartController.innerRadius * 2 && fontSize < maxFontSize) {
								fontSize += 1;
							} else {
								fontSize -= 1;
								break;
							}
						} while (true)
						ctx.restore();
					}
					centers[0].font = helpers.fontString(fontSize, fontStyle, fontFamily);
					centers[0].fontSize = fontSize;
					centers[0].fillColor = helpers.getValueOrDefault(centers[0].fontColor, globalConfig.defaultFontColor);
					
					fontStyle = helpers.getValueOrDefault(centers[1].fontStyle, globalConfig.defaultFontStyle);
					fontFamily = helpers.getValueOrDefault(centers[1].fontFamily, globalConfig.defaultFontFamily);

					if (centers[1].fontSize) {
						fontSize = centers[1].fontSize;
					} else {
						// figure out the best font size, if one is not specified
						ctx.save();
						fontSize = helpers.getValueOrDefault(centers[1].minFontSize, 1);
						maxFontSize = helpers.getValueOrDefault(centers[1].maxFontSize, 256);
						maxText = helpers.getValueOrDefault(centers[1].text, centers[1].text);
						do {
							ctx.font = helpers.fontString(fontSize, fontStyle, fontFamily);
							var textWidth = ctx.measureText(maxText).width;
							if (textWidth < chartController.innerRadius * 2 && fontSize < maxFontSize) {
								fontSize += 1;
							} else {
								fontSize -= 1;
								break;
							}
						} while (true)
						ctx.restore();
					}
					centers[1].font = helpers.fontString(fontSize, fontStyle, fontFamily);
					centers[1].fontSize = fontSize;
					centers[1].fillColor = helpers.getValueOrDefault(centers[1].fontColor, globalConfig.defaultFontColor);
					

					chartController.center = {
						center1 : centers[0],
						center2 : centers[1],
						onClick : chartController.config.options.elements.center.onClick
					}
				}
			},
			beforeDraw : function(chartController) {
				var helpers = ChartJs.Chart.helpers, ctx, config, centerX, centerY, datas, total = 0;
				var centers = chartController.config.options.elements.center;
				if (chartController.center) {
					ctx = chartController.chart.ctx;
					centerX = (chartController.chartArea.left + chartController.chartArea.right) / 2;
					centerY = (chartController.chartArea.top + chartController.chartArea.bottom) / 2;
					chartController.center.x = centerX;
					chartController.center.y = centerY;
					ctx.save();
					ctx.textAlign = 'center';
					ctx.textBaseline = 'middle';
					ctx.font = helpers.fontString(chartController.center.center1.fontSize, chartController.center.center1.fontStyle, chartController.center.center1.fontFamily);
					ctx.fillStyle = chartController.center.center1.fillColor;
					ctx.fillText(chartController.center.center1.text, chartController.center.x, centerY - chartController.center.center1.fontSize - 3);
					ctx.font = helpers.fontString(chartController.center.center2.fontSize, chartController.center.center2.fontStyle, chartController.center.center2.fontFamily);
					ctx.fillStyle = chartController.center.center2.fillColor;
					ctx.fillText(chartController.center.center2.text, centerX, centerY);
					ctx.restore();
					if (chartController.center.onClick && !chartController.center.addEventListener) {
						chartController.center.addEventListener = true;
						chartController.chart.canvas.addEventListener("mousemove", function(chartController, config) {
							return function(event) {
								var x, y;
								x = event.layerX;
								y = event.layerY;
								if (x >= (config.x - chartController.innerRadius) && x <= (config.x + chartController.innerRadius) && y <= (config.y + chartController.innerRadius)
										&& y >= (config.y - chartController.innerRadius)) {
									event.target.parentElement.style.cursor = "pointer";
									config.inLink = true;
								} else {
									event.target.parentElement.style.cursor = "";
									config.inLink = false;
								}
							}
						}(chartController, chartController.center), false);
						chartController.chart.canvas.addEventListener("click", clickHandlerFactory(chartController, chartController.center), false);
					}
				}
				function clickHandlerFactory(chartController, config) {
					return function(event) {
						if (config.inLink) {
							config.onClick(chartController, config, event);
						}
					}
				}
			}
		});
		
		function getPageFormData(pageModel, fields) {
			var getter, setter, formaData = {};
			if (fields && pageModel) {
				if (angular.isArray(pageModel)) {
					formaData = [];
					angular.forEach(pageModel, function(model, index) {
						formaData[index] = getPageFormData(model, fields);
					});
				} else {
					angular.forEach(fields, function(field, key) {
						getter = $parse(field);
						setter = getter.assign;
						try{
							if (getter(pageModel) !== undefined) {
								setter(formaData, getter(pageModel));
							}
						}catch(e){
						}
					});
				}
			} else {
				formaData = pageModel;
			}
			return formaData;
		}
		function getPageFormFields(pageConfig) {
			var fields;
			if (!pageConfig) {
				return fields;
			}
			angular.forEach(pageConfig, function(column){
				if(column.field && (!column.cellTemplate || column.cellTemplate.indexOf('fs-grid-config="row.entity"') != -1)){
					fields = fields || {};
					fields[column.field] = column.field;
				}
			});
			angular.forEach(pageConfig.gridConfigs, function(grid){
				if(grid.model){
					fields = fields || {};
					fields[grid.model] = grid.model;
				}
			});
			angular.forEach(pageConfig.formConfigs, function(form){
				angular.forEach(form.gridConfigs, function(grid){
					if(grid.model){
						fields = fields || {};
						fields[grid.model] = grid.model;
					}
				});
			});
			return fields;
		}
		function isFormChanged($event) {
			if (hasChanged()) {
				($event || $window.event).returnValue = 'Are you sure to leave this page?';
				return 'Are you sure to leave this page?';
			} else {
				return undefined;
			}
		}
		function hasChanged() {
			var i = 0, scope, dataKey, pageData, fields, changed;
			if (!$rootScope._formDataKey) {
				return false;
			}
			for (i = 0; i < $rootScope._formDataKey.length; i++) {
				dataKey = $rootScope._formDataKey[i];
				scope = $rootScope._formScope[dataKey];
				fields = $rootScope._formFields[dataKey];
				pageData = scope.$eval(dataKey);
				changed = commonService.hash(getPageFormData(pageData, fields)) != $rootScope._formDataHashCode[dataKey];
				if (changed) {
					return changed;
				}
			}
			return false;
		}
		function isIgnoreHistory (state) {
			var pattern = /(?:.*\.(?:create)|(?:createContinue)|(?:createReject)|(?:update)|(?:updateContinue)|(?:updateReject)|(?:delete)|(?:deleteReject))/;
			return pattern.test(state.name);
		}
	}
})(angular);
